#!/bin/sh
# Copyright 2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# dnsmasq-resolv.conf updater
# Written by Roy Marples (uberlord@gentoo.org)

# This is very important!
# We assume that we are a local dns cache - after all, why would a server
# use resolvconf?
# Now that we have assumed this, we also assume that generic DHCP clients
# will enter their domains and search domains ONLY in the "search" field
# in their resolv.confs and VPN clients will put the domain they are for
# into the domain field only.
# This allows dnsmasq to forward domains for a specific VPN domain to the
# VPN nameserver and everything else to the standard name servers.

# A sample dnsmasq config that works as above is like so
#domain-needed
#interface=lo
#resolv-file=/etc/dnsmasq-resolv.conf
#conf-file=/etc/dnsmasq-resolvconf.conf

# The last step is to configure dns configuration for /etc/resolv.conf
# for the lo interface. In Gentoo we set it up like so in /etc/conf.d/net
#dns_servers_lo="127.0.0.1"

# Load our variables from resolvconf
VARS="$(resolvconf -v)"
eval "${VARS}"

DNSMASQRESOLV="/etc/dnsmasq-resolv.conf"
DNSMASQCONF="/etc/dnsmasq-resolvconf.conf"

NEWCONF="# Generated by resolvconf\n"
NEWRESOLV="${NEWCONF}"

# Using DBUS means that we never have to restart the daemon
# This is important as it means we should not drop DNS queries
# whilst changing DNS options around. However, DBUS support is optional
# so we need to validate a few things first.
# Check for DBus support in the binary
DBUS=no
if dnsmasq --version 2>/dev/null | \
grep -q "^Compile time options.*[[:space:]]DBus[[:space:]]" \
; then
	# Sanity - check that dnsmasq and dbus are running
	if [ -x /etc/init.d/dbus -a -x /etc/init.d/dnsmasq ] ; then
		if /etc/init.d/dbus --quiet status && /etc/init.d/dnsmasq --quiet status ; then
			DBUS=yes
			NEWCONF="${NEWCONF}\n# Domain specific servers will be sent over dbus\n\nenable-dbus\n"
		fi
	fi
fi

uniqify() {
    local result=
    while [ -n "$1" ] ; do
		case " ${result} " in
			*" $1 "*) ;;
			*) result="${result} $1" ;;
		esac
		shift
	done
    echo "${result# *}"
}

# If we only have domain information then put it in search too
[ -z "${NEWSEARCH}" -a -z "${NEWNS}" ] && NEWSEARCH="${NEWDOMAIN}"

for N in ${NEWSEARCH} ; do
	case " ${NEWSL} " in
		*" ${N%,*} "*) ;;
		*) NEWSL="${NEWSL} ${N%,*}" ;;
	esac
	case "\n${NEWRESOLV}\n" in
		*"\nnameserver ${N#*,}\n"*) ;;
		*) NEWRESOLV="${NEWRESOLV}nameserver ${N#*,}\n" ;;
	esac
done
for N in ${NEWNS} ; do
	case "\n${NEWRESOLV}\n" in
		*"\nnameserver ${N}\n") ;;
		*) NEWRESOLV="${NEWRESOLV}nameserver ${N}\n" ;;
	esac
done
[ -n "${NEWSL}" ] && NEWRESOLV="${NEWRESOLV}search${NEWSL}\n"

DBUSDEST=
for DN in $(uniqify ${NEWDOMAIN}) ; do
	if [ "${DBUS}" = "yes" ] ; then
		IP=${DN#*,}
		SIFS=${IFS-y} OIFS=$IFS
		IFS=.
		set -- ${IP}
		NUM="0x$(printf "%02x" $1 $2 $3 $4)"
		if [ "${SIFS}" = "y" ] ; then
			IFS=$OIFS
		else
			unset IFS
		fi
		DBUSDEST="${DBUSDEST} uint32:$(printf "%d" ${NUM}) string:${DN%,*}"
	else
		NEWCONF="${NEWCONF}server=/${DN%,*}/${DN#*,}\n"
	fi
done

RELOAD="no"
if [ -e "${DNSMASQCONF}" ] ; then
	if [ "$(cat "${DNSMASQCONF}")" != "$(printf "${NEWCONF}")" ] ; then
		RELOAD="yes"
		printf "${NEWCONF}" > "${DNSMASQCONF}"
	fi
else
	RELOAD="yes"
	printf "${NEWCONF}" > "${DNSMASQCONF}"
fi
if [ -e "${DNSMASQRESOLV}" ] ; then
	if [ "$(cat "${DNSMASQRESOLV}")" != "$(printf "${NEWRESOLV}")" ] ; then
		RELOAD="yes"
		printf "${NEWRESOLV}" > "${DNSMASQRESOLV}"
	fi
else
	# dnsmasq polls this file so no need to set RELOAD="yes"
	printf "${NEWRESOLV}" > "${DNSMASQRESOLV}"
fi

if [ "${RELOAD}" = "yes" -a -x /etc/init.d/dnsmasq ] ; then
	/etc/init.d/dnsmasq --quiet --nodeps conditionalrestart
fi

if [ "${DBUS}" = "yes" ] ; then
	if [ "${RELOAD}" != "yes" -a -x /etc/init.d/dnsmasq ] ; then
		/etc/init.d/dnsmasq --quiet reload
	fi
	# Send even if emtpy so old servers are cleared
	dbus-send --system --dest=uk.org.thekelleys.dnsmasq \
 		/uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers \
  		${DBUSDEST}
fi

# vim: ts=4 :
